El conjunto de datos del titanic es ampliamente concido en la comunidad del ML. Es más, forma parte de los retos de iniciación en la plataforma kaggle.
Este conjunto de datos, es la representación de las personas que embarcaron en el titanic. En el, se recogen multitud de datos sobre cada persona, relativos a su edad, pais y clase en la que embarcaron, además de si sobrevivieron o no.
Este cojunto de datos tiene la posibilidad de explicar algunos datos de la catastrofe. Puede aclarar si hubo algún condicionante para la muerte o supervivencia de las personas más allá del puro azar.
Este cojunto de datos pretende elaborar un modelo predictivo y con el responder a la pregunta: ¿Qué tipo de personas tenían más probabilidades de sobrevivir?
Antes de integrar, vamos a describir las variables que caracterízan a estos datos:
PassengerId Id del pasajero
Name Nombre del pasajero en formato cadena.
Sex Factor con los niveles male/female.
Age Valor numérico con la edad, los niños menores a un año vienen especificados en fracción.
Pclass Factor con la clase de pasajero/personal.
Embarked Factor con el emarque de la persona.
Cabin Factor con el camarote
Ticket billete de cada persona (NA para la tripulación).
Fare Valor numérico con el precio del ticket (NA para miembros de la tripulación musicos y empleados de la compañia).
SibSp Factor con el número de conyuges fuera (adaptado del conjunto de datos de vanderbild).
Parch Factor con el número de padres, hijos a bordo( importado del conjunto de datos de vanderbild).
Survived Factor con dos niveles indicando si sobrevivió o no.
Escogemos las columnas que serán factores:
factors = c("Sex"="factor","Pclass"="factor","Cabin"="factor", "Embarked"="factor","SibSp"="factor","Parch"="factor","Survived"="factor");
Cargamos los datos:
titanicData <- read.csv('titanic.csv', stringsAsFactors = FALSE, colClasses = factors );
summary(titanicData);
## PassengerId Survived Pclass Name Sex
## Min. : 1.0 0:549 1:216 Length:891 female:314
## 1st Qu.:223.5 1:342 2:184 Class :character male :577
## Median :446.0 3:491 Mode :character
## Mean :446.0
## 3rd Qu.:668.5
## Max. :891.0
##
## Age SibSp Parch Ticket Fare
## Min. : 0.42 0:608 0:678 Length:891 Min. : 0.00
## 1st Qu.:20.12 1:209 1:118 Class :character 1st Qu.: 7.91
## Median :28.00 2: 28 2: 80 Mode :character Median : 14.45
## Mean :29.70 3: 16 3: 5 Mean : 32.20
## 3rd Qu.:38.00 4: 18 4: 4 3rd Qu.: 31.00
## Max. :80.00 5: 5 5: 5 Max. :512.33
## NA's :177 8: 7 6: 1
## Cabin Embarked
## :687 : 2
## B96 B98 : 4 C:168
## C23 C25 C27: 4 Q: 77
## G6 : 4 S:644
## C22 C26 : 3
## D : 3
## (Other) :186
Los datos de interés de ese cojunto de datos serán los que nos aporten algo de información sobre las personas pero a nivel de cojunto, es decir datos como nombre, identificador de pasajero o número de ticket no nos resultan de utilidad. Por lo que podemos crear un conjunto de datos solamente con los datos adecuados:
cols_remove <- c("PassengerId", "Name", "Ticket")
titanicData <- titanicData[, !(colnames(titanicData) %in% cols_remove)]
summary(titanicData);
## Survived Pclass Sex Age SibSp Parch Fare
## 0:549 1:216 female:314 Min. : 0.42 0:608 0:678 Min. : 0.00
## 1:342 2:184 male :577 1st Qu.:20.12 1:209 1:118 1st Qu.: 7.91
## 3:491 Median :28.00 2: 28 2: 80 Median : 14.45
## Mean :29.70 3: 16 3: 5 Mean : 32.20
## 3rd Qu.:38.00 4: 18 4: 4 3rd Qu.: 31.00
## Max. :80.00 5: 5 5: 5 Max. :512.33
## NA's :177 8: 7 6: 1
## Cabin Embarked
## :687 : 2
## B96 B98 : 4 C:168
## C23 C25 C27: 4 Q: 77
## G6 : 4 S:644
## C22 C26 : 3
## D : 3
## (Other) :186
Para comprobar si los datos contienen elementos vacíos se ejecuta la siguiente sentencia.
colSums(is.na(titanicData))
## Survived Pclass Sex Age SibSp Parch Fare Cabin
## 0 0 0 177 0 0 0 0
## Embarked
## 0
Se puede observar que la columna Age contiene 177 valores nulos. Existen diferentes políticas para el tratamiento de los valores nulos:
Eliminarlos: En Ocasiones, compensa eliminar estas filas, ya que pueden generar distorsiones a la hora de hacer cálculos con las columnas que contienen los valores nulos.
Reemplazo: Se podrían reemplazar los valores por la media, la mediana o la moda. Estas medidas se pueden intentar particular en función de otras columnas para que no siempre sean los mismos para todas las entradas nulas.
Asignación de una categoría: Si se discretizan los datos en, por ejemplo, rangos de edad, se puede particularizar todos los valores nulos en una categoría especial llamada “edad desconocida”.
Predicción de los valores nulos: Por último, se pueden inferir los valores mediante predicciones.
En este caso, se van a inferir los valores en función de otros parámentros. Para hacer esto, partimos de que es muy probable que la edad media de las personas que viajan en Pclass3 es diferente a la edad media de las personas que viajan en Pclass1. Además, esa edad será diferente en función de si estamos ante un hombre o una mujer. Por tanto, para inferir los valores de edad perdidos, se agrupa por Sex y Pclass, para posteriormente calcular las medianas de cada serie agrupada.
Primero, se calcula la media y la mediana de edad en función de la clase y el género del pasajero.
by_sex_class <- titanicData %>% group_by(Sex, Pclass) %>% summarise(mean = mean(Age, na.rm = TRUE), median = median(Age, na.rm = TRUE))
by_sex_class
## # A tibble: 6 x 4
## # Groups: Sex [2]
## Sex Pclass mean median
## <fct> <fct> <dbl> <dbl>
## 1 female 1 34.6 35
## 2 female 2 28.7 28
## 3 female 3 21.8 21.5
## 4 male 1 41.3 40
## 5 male 2 30.7 30
## 6 male 3 26.5 25
Se observa que la media y la mediana de edad varía en función del género y la clase en la que viajaban. Se procede a rellenar los valores nulos en la columna de edad por los valores de mediana en función de Sex y Pclass.
titanicData$Age[titanicData$Sex == "female" & titanicData$Pclass == "1" & is.na(titanicData$Age)] <- by_sex_class$median[by_sex_class$Sex == "female" & by_sex_class$Pclass == "1"]
titanicData$Age[titanicData$Sex == "female" & titanicData$Pclass == "2" & is.na(titanicData$Age)] <- by_sex_class$median[by_sex_class$Sex == "female" & by_sex_class$Pclass == "2"]
titanicData$Age[titanicData$Sex == "female" & titanicData$Pclass == "3" & is.na(titanicData$Age)] <- by_sex_class$median[by_sex_class$Sex == "female" & by_sex_class$Pclass == "3"]
titanicData$Age[titanicData$Sex == "male" & titanicData$Pclass == "1" & is.na(titanicData$Age)] <- by_sex_class$median[by_sex_class$Sex == "male" & by_sex_class$Pclass == "1"]
titanicData$Age[titanicData$Sex == "male" & titanicData$Pclass == "2" & is.na(titanicData$Age)] <- by_sex_class$median[by_sex_class$Sex == "male" & by_sex_class$Pclass == "2"]
titanicData$Age[titanicData$Sex == "male" & titanicData$Pclass == "3" & is.na(titanicData$Age)] <- by_sex_class$median[by_sex_class$Sex == "male" & by_sex_class$Pclass == "3"]
Se vuelve a comprobar si existen valores nulos.
colSums(is.na(titanicData))
## Survived Pclass Sex Age SibSp Parch Fare Cabin
## 0 0 0 0 0 0 0 0
## Embarked
## 0
Se han eliminado los valores nulos. Ahora, se comprueba que el summary no difiere mucho del original.
summary(titanicData)
## Survived Pclass Sex Age SibSp Parch Fare
## 0:549 1:216 female:314 Min. : 0.42 0:608 0:678 Min. : 0.00
## 1:342 2:184 male :577 1st Qu.:21.50 1:209 1:118 1st Qu.: 7.91
## 3:491 Median :26.00 2: 28 2: 80 Median : 14.45
## Mean :29.11 3: 16 3: 5 Mean : 32.20
## 3rd Qu.:36.00 4: 18 4: 4 3rd Qu.: 31.00
## Max. :80.00 5: 5 5: 5 Max. :512.33
## 8: 7 6: 1
## Cabin Embarked
## :687 : 2
## B96 B98 : 4 C:168
## C23 C25 C27: 4 Q: 77
## G6 : 4 S:644
## C22 C26 : 3
## D : 3
## (Other) :186
La media de edad ha bajado ligeramente, pero en general los datos se mantienen estables aún habiendo inferido 177 entradas.